﻿using System;
using System.ComponentModel;
using System.Threading;
using System.Web;
using System.Xml;

using Rsdn.Janus.Framework;
using Rsdn.Janus.Framework.Ipc;
using Rsdn.Janus.Log;
using Rsdn.SmartApp;

namespace Rsdn.Janus
{
    /// <summary>
    /// Слушает именованный канал на предмет передачи в приложение тем
    /// для загрузки.
    /// </summary>
    internal class GoJanusListener
    {
        private readonly IServiceProvider _provider;

        private DelayedMessage messages;
        #region Private members
        private const string _pipeName = "JanusPipe";

        private readonly ServerPipeConnection _connection;
        #endregion

        #region Ctor
        private GoJanusListener(IServiceProvider provider)
        {
            _provider = provider;
            _connection = new ServerPipeConnection(_pipeName, 512, 512, 5000);
            messages = new DelayedMessage(provider, "Невозможно извлечь номер сообщения форума RSDN из ссылки (ссылок):");
            var th = new Thread(Listen)
                {
                    IsBackground = true,
                    Priority = ThreadPriority.Lowest,
                    CurrentUICulture = Thread.CurrentThread.CurrentUICulture
                };

            th.Start();
        }
        #endregion

        public static void Start(IServiceProvider provider)
        {
            new GoJanusListener(provider);
        }

        #region ProcessRequest & Listen
        private void ProcessRequest(string request)
        {
            try
            {
                var document = new XmlDocument();
                string requestMod = HttpUtility.XmlTextEncode(request);
                document.LoadXml(requestMod);

                if (document.DocumentElement != null)
                    switch (document.DocumentElement.Name)
                    {
                        case "goto-message":
                            GotoMessage(document);
                            break;
                        case "download-topic":
                            DownloadTopic(document);
                            break;
                        case "protocol-request":
                            ProtocolRequest(document);
                            break;
                    }
            }
            catch (Exception ex)
            {
                _provider
                    .LogWarning(
                        string.Format(SR.GoJanusListener.InvalidReceivedMessage, ex.Message));
            }
        }

        private void Listen()
        {
            while (true)
                try
                {
                    _connection.Connect();
                    ProcessRequest(_connection.Read());
                }
                catch (Exception ex)
                {
                    _provider.LogWarning(
                        string.Format(SR.GoJanusListener.PipeListenerErrorMessage, ex.Message));
                }
                finally
                {
                    _connection.Disconnect();
                }
        }
        #endregion

        #region Protocol Handlers
        private void DownloadTopic(XmlNode document)
        {
            //int mid = int.Parse(document.SelectSingleNode("/download-topic/message-id").InnerText);
            //string hint = document.SelectSingleNode("/download-topic/hint").InnerText;

            int mid = 0;
            string hint = "";
            int version = 0;

            XmlNode firstChild = document.FirstChild;
            int messageId = 0;
            if (firstChild.Name == "download-topic")
            {
                XmlElement xmlElement1 = firstChild["version"];
                if (xmlElement1 != null)
                {
                    version = int.Parse(xmlElement1.InnerText);
                }
                if (version == 0)
                {
                    XmlElement xmlElement2 = firstChild["message-id"];
                    if (xmlElement2 != null)
                    {
                        messageId = int.Parse(xmlElement2.InnerText);
                    }
                }

                XmlElement xmlElement3 = firstChild["url"];
                if (xmlElement3 != null)
                {
                    string link = xmlElement3.InnerText;
                    bool isValid = GetMessageId(link, ref messageId);
                    mid = messageId;
                    if (!isValid)
                    {
                        messages.AddErrorChildLine(link);
                        //NotifyAboutError(
                        //    String.Format("Невозможно извлечь номер сообщения форума RSDN из ссылки\n{0}", link));
                        return;
                    }
                }

                XmlElement xmlElement4 = firstChild["hint"];
                if (xmlElement4 != null)
                {
                    hint = xmlElement4.InnerText;
                }
            }

            _provider
                .GetRequiredService<IOutboxManager>()
                .DownloadTopics
                .Add(SR.Forum.DownloadTopicIESource, mid, hint);
        }

        private void ProtocolRequest(XmlNode document)
        {
            var path = document.SelectSingleNode("/protocol-request/path").InnerText;

            _connection.WriteBytes(
                ApplicationManager
                    .Instance
                    .ProtocolDispatcher
                    .DispatchRequest(path)
                    .GetPackedBytes());
        }

        private void GotoMessage(XmlNode document)
        {
            XmlNode firstChild = document.FirstChild;
            int messageId = 0;
            if (firstChild.Name == "goto-message")
            {
                XmlElement xmlElement1 = firstChild["version"];
                if (xmlElement1 != null)
                {
                    int version = int.Parse(xmlElement1.InnerText);
                    XmlElement xmlElement3 = firstChild["url"];
                    if (xmlElement3 != null)
                    {
                        string link = xmlElement3.InnerText;
                        GotoMessage(link);
                        return;
                    }
                }
                XmlElement xmlElement2 = firstChild["message-id"];
                if (xmlElement2 != null)
                {
                    messageId = int.Parse(xmlElement2.InnerText);
                }
            }
            XmlElement xmlElement = document["version"];

            //int mid = int.Parse(document.SelectSingleNode("/goto-message/message-id").InnerText);
            if (messageId > 0)
            {
                GotoMessage(messageId);
            }
        }

        private void GotoMessage(string link)
        {
            if (!string.IsNullOrEmpty(link))
            {
                int messageId = 0;
                bool isValid = GetMessageId(link, ref messageId);

                if (messageId > 0)
                {
                    GotoMessage(messageId);
                }
                else
                {
                    messages.AddErrorChildLine(link);
                    //NotifyAboutError(String.Format("Невозможно извлечь номер сообщения форума RSDN из ссылки\n{0}", link));
                    _provider.OpenUrlInBrowser(link);
                }
            }
        }

        private bool GetMessageId(string link, ref int messageId)
        {
            bool isValid = true;
            try
            {
                //string input = ((TextBox)sender).Text;
                string input = link;

                if (!string.IsNullOrEmpty(input))
                {
                    JanusProtocolInfo janusProtocolInfo = JanusProtocolInfo.Parse(input);
                    if (janusProtocolInfo != null && janusProtocolInfo.IsId)
                    {
                        messageId = janusProtocolInfo.Id;
                    }
                    else
                    {
                        messageId = int.Parse(input);
                    }
                }
                else
                {
                    isValid = false;
                }
            }
            catch
            {
                isValid = false;
            }
            return isValid;
        }


        private void GotoMessageInternal(int messageId)
        {
            WindowActivator.ActivateWindow(MainForm.GetCaption());

            // download topic if not found
            if (!ApplicationManager.Instance.ForumNavigator.SelectMessage(messageId))
            {
                IOutboxManager outboxManager = _provider.GetRequiredService<IOutboxManager>();
                outboxManager.AddTopicForDownloadWithConfirm(messageId);
                //outboxManager.
            }
        }

        private void GotoMessage(int messageId)
        {
            //GotoMessageInternal(messageId);
            AsyncOperation uiAsyncOperation = _provider.GetRequiredService<IUIShell>().CreateUIAsyncOperation();
            uiAsyncOperation.Post(delegate { GotoMessageInternal(messageId); });
        }

        #endregion
    }
}
